#include "Plan.h"
#include "NPCEntity.h" 
#include "World.h"

// empty constructor
Plan::Plan()
{
	plan__ == std::list<Action*>();
	ActionMove * MoveToMe = new ActionMove(NULL) ;
	addAction(MoveToMe);
	name__ = "idle";
	reward__ = std::list<std::pair<std::string,float> >() ;
	timeElapsed__ = 0 ;
} 

// constructor by name
Plan::Plan(std::string name)
{
	plan__ == std::list<Action*>();
	name__ = name ;
}

// copy constructor
Plan::Plan(const Plan& p)
{
	this->plan__ = p.plan__ ;
	this->name__ = p.name__ ;
	this->reward__ = p.reward__ ;
}

// full constructor with parameters
Plan::Plan(std::list<Action *> plan,std::string name,std::list<std::pair<std::string,float> > reward)
{
	plan__ = plan ;
	name__ = name ;
	reward__ = reward ;
}


// destructor
Plan::~Plan()
{

}


// adds an action to the plan
void Plan::addAction(Action * a)
{
	plan__.push_back(a);
}

void Plan::removeFirstAction()
{
	
	std::list<Action*>::iterator it = plan__.begin() ;
	if(it != plan__.end())
	{
		delete *it ;
		plan__.erase(it) ;
	}
}

// returns pointer to the first action in the plan
Action * Plan::getFirstAction()
{
	return plan__.front();
}

// time elapsed ++
void Plan::timeElapsedUp()
{
	float timeSinceLastFrame = World::getWorld()->elapsedTime() ;
	timeElapsed__ += timeSinceLastFrame ;
}

float Plan::getTimeElapsed()
{
	return timeElapsed__ ;
}

void Plan::setElapsedTime(float t)
{
	timeElapsed__ = t ;
}

// removes the first action in the plan
// 
void Plan::removeFirstActionFromPlan()
{
	std::cout << "warning depreciated method Plan::removeFirstActionFromPlan()" << std::endl ;
	return plan__.pop_front();
}

// returns the whole plan
std::list<Action*> Plan::getPlan()
{
	return plan__ ;
}

// returns the name of the current plan
std::string Plan::getName()
{
	return this->name__ ;
}

// returns the reward (i.e. desires' modifiers) associated to the plan
std::list<std::pair<std::string,float> > Plan::getReward()
{
	return reward__ ;
}

// execute action from the plan and then reward if success
bool Plan::usePlan(NPCEntity * e)
{	
		if(!isPlanAchieved())
		{
			// if the action is successfully performed
			if(getFirstAction()->execute(e))
			{
				// remove it from the plan
				removeFirstAction() ;

				if(isPlanAchieved())
				{
					e->getRewardForAchievedPlan(this) ;
					return true ;
				}
				
			}
			else
			{
				// else return false (i.e. plan not achieved yet)
				return false ;
			}
		}
		else
		{
			// if the plan is empty, it is considered as achieved successfully and the entity, gets the reward
			e->getRewardForAchievedPlan(this) ;
	
			if(debug[Debug::PLAN_INFO])
			{
				 std::cout << "plan achieved successfully" << std::endl ;
			}
			return true ;
		}
	
		return false ;
}

// sets a news name
void Plan::setName(std::string name)
{
	name__ = name ;
}

// if the stack is empty then the plan is achieved
bool Plan::isPlanAchieved()
{
	return plan__.size() == 0 ;
}

void Plan::changePlanTo(std::string planName)
{

	if(debug[Debug::PLAN_INFO])
	{
		std::cout << "switching plan to a new one : " << planName << std::endl ;
	}
	// clear all previous data from the plan
	plan__.clear() ;
	setName(planName) ;
	reward__.clear() ;
	setElapsedTime(0);


	// and choose one appropriated
	if(planName == "Die")
	{
		ActionDie * die = new ActionDie() ;
		addAction(die);

		std::pair<std::string,float> rewardAgressivity ;
		reward__.push_front(rewardAgressivity) ;
	}
	
	if(planName == "MoveAndAttack")
	{
		ActionPatrol * patrol = new ActionPatrol(60,"hostiles") ;
		ActionAttack * attack = new ActionAttack();

		addAction(patrol);
		addAction(attack);

		std::pair<std::string,float> rewardAgressivity = std::pair<std::string,float>("Agressivity",-0.7);
		reward__.push_front(rewardAgressivity) ;
	}

	if(planName == "FindAllies")
	{
		ActionTurnAround * turnAround = new ActionTurnAround(120,1) ;
		ActionPatrol * patrol = new ActionPatrol(60,"allies") ;
		addAction(turnAround);
		addAction(patrol);

		std::pair<std::string,float> rewardAgressivity = std::pair<std::string,float>("Banding",-0.1);
		std::pair<std::string,float> rewardSurvival = std::pair<std::string,float>("Survival",-0.2);
		reward__.push_front(rewardAgressivity) ;
		reward__.push_front(rewardSurvival) ;
	}

	if(planName == "FleeToSurvive")
	{
		ActionFlee * flee = new ActionFlee() ;

		addAction(flee);

		//std::pair<std::string,float> rewardBanding = std::pair<std::string,float>("Banding",0.2);
		std::pair<std::string,float> rewardSurvival = std::pair<std::string,float>("Survival",-0.6);
		std::pair<std::string,float> rewardSleep = std::pair<std::string,float>("Sleep",0.1);
		reward__.push_front(rewardSurvival) ;
		//reward__.push_front(rewardBanding) ;
		reward__.push_front(rewardSleep) ;
	}

	if(planName == "Wander")
	{
		ActionTurnAround * turnAround = new ActionTurnAround(120,3) ;
		ActionPatrol * patrol = new ActionPatrol(30) ;

		addAction(turnAround);
		addAction(patrol);

		std::pair<std::string,float> rewardWander = std::pair<std::string,float>("Wander",-0.5);
		std::pair<std::string,float> rewardHunger = std::pair<std::string,float>("Hunger",0.15);
		reward__.push_front(rewardWander) ;
		reward__.push_front(rewardHunger) ;
	}

	if(planName == "FindTreasure")
	{
		ActionGetItem * treasure = new ActionGetItem("item_treasure") ;
		ActionPatrol * patrol = new ActionPatrol(60,"treasure") ;
		ActionTurnAround * turnAround = new ActionTurnAround(120,3) ;

		addAction(turnAround);
		addAction(patrol);
		addAction(treasure);

		std::pair<std::string,float> rewardGreed = std::pair<std::string,float>("Greed",-0.5);
		reward__.push_front(rewardGreed) ;
	}

	if(planName == "FindAndEatFood")
	{
		ActionPatrol * patrol = new ActionPatrol(10,"all_eatable") ;
		ActionHunt * hunt = new ActionHunt();
		ActionGetItem * eat = new ActionGetItem("all_eatable") ;
		

		addAction(patrol);
		addAction(hunt);
		addAction(eat);


		std::pair<std::string,float> rewardHunger = std::pair<std::string,float>("Hunger",-0.5);
		reward__.push_front(rewardHunger) ;
	}

	if(planName == "GetSomeRest")
	{
		ActionSleep * sleep = new ActionSleep() ;

		addAction(sleep);

		std::pair<std::string,float> rewardSleep = std::pair<std::string,float>("Sleep",-0.1);
		std::pair<std::string,float> rewardWander = std::pair<std::string,float>("Wander",0.2);

		
		reward__.push_front(rewardSleep) ;
		reward__.push_front(rewardWander) ;

	}

	if(planName == "idle")
	{
		ActionPatrol * patrol = new ActionPatrol(5);
		addAction(patrol);
		std::pair<std::string,float> rewardWander = std::pair<std::string,float>("Wander",0.01);
		reward__.push_front(rewardWander) ;
	} 
}

// checks if the plan has to be cancelled
bool Plan::planCancel()
{
     if(plan__.size() != 0)
     {
          return !((getFirstAction())->checkConditions()) ;
     }
     else
     {
         return true ;
     }  
}
